#include "POEMv1.h"

//debug
#define DEBUG 1
const double P1_wWg = 1.5e-6; // regular Waveguide width
const double P1_wIO = 2.5e-6; //
const double P1_aIO = 0;
const double P1_wTrch = 2.5e-6;

const double P1_DY = 2900e-6;

double EAM_A(double l=100e-6, double wPm=2.5e-6); // baseline design for POEMv1.0, small pads.
double EAM_B(double l=100e-6, double lEx=0e-6, double wPm=2.5e-6, int padType=0); // EAM design B, large pads, lEx: extended active length to the taper.
double POEM_IO(double l, double a, double w1, double w2); // input/output port, l is length; a is the I/O waveguide angle to the edge in degree; w1, guiding waveguide width; w2, input width 
void padsVLSI(bool FlagShort);

double p_mmi_1x2();
double test_mmi_set();
double mmi_1x2_unit(double lMMI, double wMMI, double wWg, double wTrch=-1);
double OTDM_A();
double OTDM_B();
double OTDM_A_unit(int);
double OTDM_wo_IO();


double hybridEAM_IO(double, double);
void hybridEAM_array(int);

void TLM_Rect(int TLMtype=0, double wMesa=-1);
void TLM_Circ();//TODO

//subcell
void cell_Frame_8x8(int);
void func_Frame_8x8(void);
void cell_EAM_Array(int);
void func_EAM_Array(int);
void cell_OTDM(int);
void func_OTDM(int);
void cell_markers_x(int);//cp: bottom left
void cell_markers_x_mesa(int);//ref to pmesa layer
void func_markers_x(int);
void cell_markers_y(int);//cp: top left
void func_markers_y(int);
void cell_markers_y2(int);//high resolution vernier cp: middle.
void cell_markers_y2_mesa(int);
void cell_Pads_TestB(int);//
void func_Pads_TestB(void);
void func_EAM_B_array(int type=0);
void cell_EAM_B_array(int);//
void pTLM_Rodwell(double gap, double w);
void nTLM_Rodwell(double gap, double w);
void cell_pTLM_Rodwell(int);
void func_pTLM_Rodwell(void);
void cell_nTLM_Rodwell(int);
void func_nTLM_Rodwell(void);
void cell_TLM_Rect(int);
void func_TLM_Rect(void);
void cell_EAM_B_TestTaper(int );
void func_EAM_B_TestTaper(int );
void cell_EAM_B_TestLen(int );
void func_EAM_B_TestLen(int );
double spiral_square_sw2(double, int);
void cell_wg_loss(int);
void cell_mmi_test(int);
void Moire_line(double, double, double, int, int RefLayer=LSI);
void func_Moire_line(int, int );
void cell_Moire_line(int);
void cell_label_polarity(int);//mark of the polarity of the mask and the PR.
void cell_PD_LD(int L); //PD LD for post process
void cell_POEM_T(int L);

// Markers 
void Dektak(void) {
	push_cp();
	skip(-20e-6);
	offset(-130e-6);	
	if (clayer == 25)
		rect(100e-6, 60e-6, 4, 4);
	
	for (int m = 0; m < 3; m++) {
		sw(20e-6, 60e-6);
		skip(20e-6);
	}
	pop_cp();
}

void Circle_align(int RefLayer) {
	
	//int Current_layer = clayer;
	double R_disc = 8e-6;
	double R_circle = 8e-6;
	double R_gap = 0.4e-6;
	
	push_cp();
	skip(120e-6);
	offset(-60e-6);
	nonius();
	offset(-80e-6);
	//layer(Current_layer);
	disc(R_disc);    
	layer(RefLayer);
	circle(R_circle, R_disc + R_gap + R_circle/2);
	pop_cp();
}

void stepper_1_Xc(void) {
// This function draws the star-shaped marker with cross. Start and end cp position is below left.	
// move the cp to the center of the star-shaped marker.
	push_cp();
    //shift the center to the bottom left corner
    skip(-134.35e-6*0.5);
    offset(134.35e-6*0.5);
	for (int n = 0; n <= 3; n++) {
		triangle(0, sqrt(0.5*1.6e-6*1.6e-6), sqrt(0.5*1.6e-6*1.6e-6), 0);
		rotate(RAD(-45));
		skip(0.8e-6);
		sw(60e-6 - 1.6e-6, 1.6e-6);
		skip(0.8e-6);
		rotate(RAD(45));
		triangle(0, -sqrt(0.5*1.6e-6*1.6e-6), -sqrt(0.5*1.6e-6*1.6e-6), 0);
		rotate(RAD(-45));
		sw(35e-6, 1.6e-6);
		rotate(RAD(45));
		skip(16e-6);
		sw(46e-6, 1.6e-6);
		skip(-46e-6 - 16e-6);
		rotate(RAD(45));
		skip(95e-6);
		rotate(RAD(-135));
	}
	pop_cp();	
}
void stepper_2c(void) {
// This function draws the square marker. Start and end cp position is below left.	
	push_cp();
    skip(-60e-6);
    offset(60e-6);    
	for (int m = 0; m <= 3; m++) {
		push_cp();
		for (int n = 0; n <= 4; n++) {
			offset(-6e-6);
			rect(57e-6, 6e-6, 4, 4);
			offset(-6e-6);
	
		}
		pop_cp();
		skip(120e-6);
		rotate(RAD(-90));
	}
	pop_cp();
}

/* The MMI design */
int main(void) {
	setfont((char *)"../maskV6_00/caps.plf");
    
    //define subcell
    //layer resolution
    setlayer_accuracy(LSI, 1e-9);
    setlayer_accuracy(LVC, 1e-9);
    setlayer_accuracy(LPMESA, 1e-9);
    setlayer_accuracy(LQW, 1e-9);
    setlayer_accuracy(LNMESA, 1e-9);
    setlayer_accuracy(LNMTL, 1e-9);
    setlayer_accuracy(LPMTL, 1e-9);
    setlayer_accuracy(LIMPL, 1e-9);
    setlayer_accuracy(LVIA, 1e-9);
    setlayer_accuracy(LPROBE, 1e-9);    
    setlayer_accuracy(LSI2, 1e-9);
    setlayer_accuracy(LSI3, 1e-9);
    
    int id_OTDM = msk_add_sublayout("POEM_OTDM", cell_OTDM);
    int id_EAM_Array = msk_add_sublayout("POEM_EAM_ARRAY", cell_EAM_Array);
    int id_Frame = msk_add_sublayout("POEM_FRAME", cell_Frame_8x8);
    int id_markers_x = msk_add_sublayout("POEM_MARKERS_X", cell_markers_x);
    int id_markers_x_mesa =  msk_add_sublayout("POEM_MARKERS_X_PMESA", cell_markers_x_mesa);
    int id_markers_y = msk_add_sublayout("POEM_MARKERS_Y", cell_markers_y);
    int id_vernier_y2 = msk_add_sublayout("POEM_VERNIER_Y2", cell_markers_y2); 
    int id_vernier_y2_mesa = msk_add_sublayout("POEM_VERNIER_Y2_PMESA", cell_markers_y2_mesa); 
    int id_EAM_B_array = msk_add_sublayout("POEM_EAM_B_ARRAY", cell_EAM_B_array);
    int id_pTLM_Rodwell = msk_add_sublayout("POEM_PTLM_Rodwell", cell_pTLM_Rodwell);
    int id_nTLM_Rodwell = msk_add_sublayout("POEM_NTLM_Rodwell", cell_nTLM_Rodwell);
    int id_TLM_Rect = msk_add_sublayout("POEM_TLM_RECT", cell_TLM_Rect);
    int id_EAM_B_TestTaper = msk_add_sublayout("POEM_EAM_B_TESTTAPER", cell_EAM_B_TestTaper);
    int id_EAM_B_TestLen = msk_add_sublayout("POEM_EAM_B_TESTLEN", cell_EAM_B_TestLen);
    int id_PD_LD = msk_add_sublayout("POEM_PD_LD",cell_PD_LD);
    int id_WG_LOSS = msk_add_sublayout("POEM_WG_LOSS",cell_wg_loss);
    
    int id_MMI_T = msk_add_sublayout("POEM_MMI_TEST",cell_mmi_test);
    int id_Moire_line = msk_add_sublayout("POEM_MOIRE_LINE",cell_Moire_line);
    int id_label_polarity = msk_add_sublayout("POEM_LABEL_POLARITY", cell_label_polarity);
    
	msk_header("", "POEMv1");
    
    
    org(0,0,0,NOFLIP);
    
    // layer(LVI)
    // spiral_square_sw2();
    
    //msk_sublayout(id_MMI_T);
    
	msk_trailer();
}

void cell_Frame_8x8(int L){
    double lSide = 7800e-6;
    //10umx10um square for each layer at the corner. 
    
    org(0,0,0,NOFLIP);
    push_cp();
    skip(-lSide*0.5);
    for(int i=0; i<taperOutLayers; i++){
        layer(taperOutID[i]);
        push_cp();
        sw2(10e-6, 10e-6, lSide-20e-6);
        pop_cp();
      }
    skip(lSide-10e-6);
    for(int i=0; i<taperOutLayers; i++){      
        layer(taperOutID[i]);
        push_cp();
        sw2(10e-6, 10e-6, lSide-20e-6);
        pop_cp();
      }
        
    //set the star mark
    double pos = lSide*0.5-100e-6;
    
    {//left bottom
    pop_cp();push_cp();    
    move(-pos,-pos,0,NOFLIP);
    
    layer(LSI);
    stepper_1_Xc();
    //layer(LVIA);
    //rect(150e-6, 150e-6, 5, 5);
    
    skip(200e-6);
    
    layer(LSI);
    stepper_2c();    
    //layer(LVIA);
    //rect(150e-6, 150e-6, 5, 5);    
    }
    
    {//right bottom
    pop_cp();push_cp();    
    move(pos,-pos,0,NOFLIP);
    
    layer(LSI);
    stepper_1_Xc();
    //layer(LVIA);
    //rect(150e-6, 150e-6, 5, 5);
    
    skip(-200e-6);
    
    layer(LSI);
    stepper_2c();
    //layer(LVIA);
    //rect(150e-6, 150e-6, 5, 5);
    }

    {//right top
    pop_cp();push_cp();    
    move(pos,pos,0,NOFLIP);
    
    layer(LSI);
    stepper_1_Xc();
    //layer(LVIA);
    //rect(150e-6, 150e-6, 5, 5);
    
    skip(-200e-6);
    
    layer(LSI);
    stepper_2c();
    //layer(LVIA);
    //rect(150e-6, 150e-6, 5, 5);
    }
    
    {//left top
    pop_cp();push_cp();    
    move(-pos,pos,0,NOFLIP);
    
    layer(LSI);
    stepper_1_Xc();
    //layer(LVIA);
    //rect(150e-6, 150e-6, 5, 5);    
    
    skip(200e-6);
    
    layer(LSI);
    stepper_2c();
    //layer(LVIA);
    //rect(150e-6, 150e-6, 5, 5);
    
    }    
    
    pop_cp();
}

void cell_markers_x(int L) {//layout the marks along +x direction
    org(0,0,0,NOFLIP);
    func_markers_x(LSI);
}
void cell_markers_y2(int L) {//along y direction
    org(0,0,0, NOFLIP);
    int LREF = LSI;
    double res = 0.1e-6;    
    for (int i=0; i<taperOutLayers; i++){
        if(taperOutID[i]!=LREF)
        {    
            vernier_resolution(res,taperOutID[i] , LREF, false);
            push_cp();
            skip(-12e-6);
            rotate(-RAD(90));
            skip(-40e-6);
            textout(taperOutName[i],20e-6);
            pop_cp();
            offset(-100e-6);
        }
    }
    org(0,0,0, NOFLIP);
    
    skip(75e-6);
    for (int i=0; i<taperOutLayers; i++){
        if(taperOutID[i]!=LREF)
        {    
            vernier_resolution(res,taperOutID[i] , LREF, true);
            push_cp();
            offset(-12e-6);
            skip(-40e-6);
            textout(taperOutName[i],20e-6);
            pop_cp();
            offset(-100e-6);
        }
    }   
}
void cell_markers_y2_mesa(int L) {//along y direction
    org(0,0,0, NOFLIP);
    int LREF = LPMESA;
    double res = 0.1e-6;    
    for (int i=0; i<taperOutLayers; i++){
        if(taperOutID[i]!=LREF)
        {    
            vernier_resolution(res,taperOutID[i] , LREF, false);
            push_cp();
            skip(-12e-6);
            rotate(-RAD(90));
            skip(-40e-6);
            textout(taperOutName[i],20e-6);
            pop_cp();
            offset(-100e-6);
        }
    }
    org(0,0,0, NOFLIP);
    
    skip(75e-6);
    for (int i=0; i<taperOutLayers; i++){
        if(taperOutID[i]!=LREF)
        {    
            vernier_resolution(res,taperOutID[i] , LREF, true);
            push_cp();
            offset(-12e-6);
            skip(-40e-6);
            textout(taperOutName[i],20e-6);
            pop_cp();
            offset(-100e-6);
        }
    }   
}



void func_markers_x(int LREF){
	double pitch = 200e-6;
    
	push_cp();	
	layer(LREF);    
	for (int i = 0; i < taperOutLayers; i++) {
        if(taperOutID[i]!=LREF)
        {
            vernier_out();
            push_cp();
            skip(-5e-6);
            rotate(-RAD(90));
            textout(taperOutName[i],20e-6);
            pop_cp();
            skip(pitch);
        }
	}
    pop_cp(); push_cp();    
    for (int i=0; i < taperOutLayers; i++) {
        if(taperOutID[i]!=LREF)
        {
            layer(taperOutID[i]);
            vernier_in();
            Dektak();
            Circle_align(LREF);
            skip(pitch);
        }    
    }
    pop_cp();
    skip(pitch*(taperOutLayers-1));	
}

void cell_markers_x_mesa(int L){
    org(0,0,0,NOFLIP);
    func_markers_x(LPMESA);	
}

void cell_markers_y(int L) {//layout the marks along -y direction
    org(0,0,0,NOFLIP);	
    func_markers_y(LSI);
}
void func_markers_y(int LREF){
    double pitch = 200e-6;		

	push_cp(); //locate at the top left corner
    offset(160e-6); //move to the left bottom corner
    push_cp();
    
	layer(LREF);    
	for (int i = 0; i < taperOutLayers; i++) {
        if(taperOutID[i]!=LREF)//skip the reference layer
        {
            vernier_out();
            push_cp();
            skip(-5e-6);
            rotate(-RAD(90));
            textout(taperOutName[i],20e-6);
            pop_cp();
            
            offset(pitch);
        }
	}
    pop_cp(); push_cp();    
    for (int i=0; i < taperOutLayers; i++) {
        if(taperOutID[i]!=LREF)//skip the reference layer
        {
            layer(taperOutID[i]);
            vernier_in();
            Dektak();
            Circle_align(LREF);
            offset(pitch);
        }    
    }
    pop_cp();
    pop_cp();
    offset(200e-6*taperOutLayers);
}


void TLM_Rect(int TLMtype, double wMesa){
// TLMtype: 0 -> P; 1 -> I; 2 -> N
    double g[]={4e-6,6e-6,9e-6,13e-6,18e-6};
    double l = 50e-6;
    double w = 100e-6;
    double lTotal = 0;
    double margin = 5e-6;
        
    if(wMesa<=0) wMesa = w;
    
    for(int i=0;i<sizeof(g)/sizeof(g[0]);i++){
     lTotal += l;
     lTotal += g[i];
    }
    lTotal +=l;
    
    push_cp();
    if(TLMtype <2){        
        skip(margin*0.5);
        layer(LPMESA);
        sw(lTotal+margin, wMesa+margin);
    }
    
    pop_cp();push_cp();
    layer(LQW);
    sw(lTotal+2*margin, wMesa+2*margin);
    
    pop_cp();push_cp();
    layer(LNMESA);
    sw(lTotal+2*margin, w+2*margin);
    
    if(TLMtype<2){
        pop_cp();push_cp();
        layer(LPMTL);
        skip(margin);
        for(int i=0;i<sizeof(g)/sizeof(g[0]);i++){
            sw(l, w);
            skip(g[i]);
        }
        sw(l, w);
    }
    if(TLMtype==2){
        pop_cp();push_cp();
        layer(LNMTL);
        skip(margin);
        for(int i=0;i<sizeof(g)/sizeof(g[0]);i++){
            sw(l, w);
            skip(g[i]);
        }
        sw(l, w);            
    }
    if(TLMtype==1){
        pop_cp();push_cp();
        layer(LIMPL);
        skip(margin);
        for(int i=0;i<sizeof(g)/sizeof(g[0]);i++){
            skip(l-0.5e-6);
            sw(g[i]+1e-6, w+2*margin);
            skip(-0.5e-6);
        }       
    }
    
    pop_cp();push_cp();
    layer(LVIA);
    skip(margin);
    for(int i=0;i<sizeof(g)/sizeof(g[0]);i++){
        sw(l, w);
        skip(g[i]);
    }
    sw(l, w);

    pop_cp();push_cp();
    double ftHeight = 20e-6;
    offset(-(w*0.5+margin));
    layer(LVC);
    char temp[10];
    for(int i=0;i<sizeof(g)/sizeof(g[0]);i++){
        skip(l-g[i]);        
        sprintf(temp, "%d", int(round(g[i]*1e6)));
        textout(temp, ftHeight);
    }   
        
    pop_cp();
    skip(lTotal+2*margin);
}

void cell_TLM_Rect(int L){   
    org(0,0,0,NOFLIP);
    func_TLM_Rect();
}
void func_TLM_Rect(void){
    double wM = 10e-6;
    double dy = 150e-6;
    
    push_cp();
    TLM_Rect(0, wM);//p TLM
    pop_cp();offset(dy);push_cp();
    TLM_Rect(2, -1);//n TLM
    pop_cp();offset(dy);push_cp();
    TLM_Rect(1, wM);//i TLM
    pop_cp();
}

void TLM_Circ(){//TODO
    //TODO
}

void pTLM_Rodwell(double gap, double w){
    double margin = 2e-6;
    double lPad = 80e-6;
    double wPad = 50e-6;

    push_cp();
    rotate(-RAD(90));
    push_cp(); 
    layer(LPMESA);
    skip(-(gap+margin)*0.5);
    sw(gap+margin, w);
    pop_cp();
    
    {layer(LQW);
    push_cp();
    skip(-(gap*0.5+wPad+30e-6));
    sw(gap+2*(wPad+30e-6), w+2*wPad+20e-6);
    pop_cp();}
    
    {layer(LNMESA);
    push_cp();
    skip(-(gap*0.5+wPad+30e-6));
    sw(gap+2*(wPad+30e-6), w+2*wPad+20e-6);
    pop_cp();}
    
    {layer(LNMTL);
    push_cp();    
    skip(gap*0.5+10e-6);
    offset((5e-6+wPad*0.5));
    sw(20e-6+wPad, 10e-6+wPad+w);
    pop_cp();
    push_cp();
    rotate(RAD(180));
    skip(gap*0.5+10e-6);
    offset((5e-6+wPad*0.5));
    sw(20e-6+wPad, 10e-6+wPad+w);
    pop_cp();    
    }
    {layer(LPMTL);//revised.
    push_cp();    
    //top
    skip(gap*0.5);
    sw(20e-6, w);
    sw(10e-6, 5e-6);    
    offset(0.5*lPad-(0.5*w-10e-6));
    sw(wPad, lPad);
    //rect(wPad, lPad, 7, 2);
    pop_cp();
    //btm
    push_cp();
    rotate(RAD(180));
    skip(gap*0.5);
    sw(20e-6, w);
    sw(10e-6, 5e-6);
    //offset(-2.5e-6);
    //rect(wPad, lPad, 7, 2);
    offset(0.5*lPad-(0.5*w-10e-6));
    sw(wPad, lPad);
    pop_cp();
    //left
    push_cp();
    rotate(RAD(90));
    offset(gap*0.5+2.5e-6);
    skip(w*0.5);
    sw(10e-6, 5e-6);
    offset(-2.5e-6);
    rect(wPad, lPad, 7, 2);      
    pop_cp();
    //right
    push_cp();
    rotate(RAD(-90));
    offset(gap*0.5+2.5e-6);
    skip(w*0.5);
    sw(10e-6, 5e-6);
    offset(-2.5e-6);
    rect(wPad, lPad, 7, 2);    
    pop_cp();}
    
    {layer(LVIA);
    push_cp();
    rect(170e-6, 120e-6+w, 5, 5);    
    pop_cp();}
    
    layer(LVC);
    double ftHeight=20e-6;
    offset(-w*0.5-ftHeight*0.5);
    skip(-ftHeight);
    char temp[10];
    sprintf(temp, "%d", int(round(gap*1e6)));
    textout(temp, ftHeight);
    
    pop_cp();
}
void nTLM_Rodwell(double gap, double w){
double margin = 2e-6;
    double lPad = 80e-6;
    double wPad = 50e-6;

    push_cp();
    rotate(-RAD(90));
    
    {layer(LQW);
    push_cp();
    skip(-(gap*0.5+wPad+30e-6));
    sw(gap+2*(wPad+30e-6), w+2*wPad+20e-6);
    pop_cp();}
    
    {layer(LNMESA);
    push_cp();
    skip(-(gap*0.5+wPad+30e-6));
    sw(gap+2*(wPad+30e-6), w+2*wPad+20e-6);
    pop_cp();}
    
    {layer(LNMTL);//revised.
    push_cp();    
    //top
    skip(gap*0.5);
    sw(20e-6, w);
    sw(10e-6, 5e-6);    
    offset(0.5*lPad-(0.5*w-10e-6));
    sw(wPad, lPad);
    //rect(wPad, lPad, 7, 2);
    pop_cp();
    //btm
    push_cp();
    rotate(RAD(180));
    skip(gap*0.5);
    sw(20e-6, w);
    sw(10e-6, 5e-6);
    //offset(-2.5e-6);
    //rect(wPad, lPad, 7, 2);
    offset(0.5*lPad-(0.5*w-10e-6));
    sw(wPad, lPad);
    pop_cp();
    //left
    push_cp();
    rotate(RAD(90));
    offset(gap*0.5+2.5e-6);
    skip(w*0.5);
    sw(10e-6, 5e-6);
    offset(-2.5e-6);
    rect(wPad, lPad, 7, 2);      
    pop_cp();
    //right
    push_cp();
    rotate(RAD(-90));
    offset(gap*0.5+2.5e-6);
    skip(w*0.5);
    sw(10e-6, 5e-6);
    offset(-2.5e-6);
    rect(wPad, lPad, 7, 2);    
    pop_cp();}
    
    {layer(LVIA);
    push_cp();
    rect(170e-6, 120e-6+w, 5, 5);    
    pop_cp();}
    
    layer(LVC);
    double ftHeight=20e-6;
    offset(-w*0.5-ftHeight*0.5);
    skip(-ftHeight);
    char temp[10];
    sprintf(temp, "%d", int(round(gap*1e6)));
    textout(temp, ftHeight);
    
    pop_cp();
}

void cell_pTLM_Rodwell(int L){
    org(0,0,0,NOFLIP);
    func_pTLM_Rodwell();
}
void func_pTLM_Rodwell(void){
    double w = 100e-6;
    double dy = 200e-6;
    double dx = w+150e-6;
    
    pTLM_Rodwell(3e-6, w);
    offset(dy);
    pTLM_Rodwell(4e-6, w);
    offset(dy);
    pTLM_Rodwell(5e-6, w);
    skip(dx);
    pTLM_Rodwell(7e-6, w);
    offset(-dy);    
    pTLM_Rodwell(9e-6, w);
    offset(-dy);
    pTLM_Rodwell(12e-6, w);
    skip(-dx);  
}
void cell_nTLM_Rodwell(int L){
    org(0,0,0,NOFLIP);
    func_nTLM_Rodwell();
}
void func_nTLM_Rodwell(void){
    double w = 100e-6;
    double dy = 200e-6;
    double dx = w+150e-6;
    
    nTLM_Rodwell(3e-6, w);
    offset(dy);
    nTLM_Rodwell(4e-6, w);
    offset(dy);
    nTLM_Rodwell(5e-6, w);
    skip(dx);
    nTLM_Rodwell(7e-6, w);
    offset(-dy);    
    nTLM_Rodwell(9e-6, w);
    offset(-dy);
    nTLM_Rodwell(12e-6, w);
    skip(-dx);
}

double POEM_IO(double l, double a=7, double w1=1.5e-6, double w2=2.5e-6){
    double lGuide = l;
    double lTaper = 100e-6;
    double lStraight = 50e-6;
    double rBend = 400e-6;
    double angBend = RAD(a);
    double lTilt = 245e-6;
    
    double wGuide = w1;
    double wIO = w2;
    double wTrch = 2.5e-6;
    double dis2Edge=0;
    
    double lPolishMark = 2.5e-6;
    double wPolishMark = 15e-6;
    
    push_cp();
    layer(LSI);
    sw2(lGuide, wTrch, wGuide);
    taper2(lStraight, wTrch, wTrch, wGuide, wIO);
    sw2(lPolishMark, wPolishMark, 2*wIO+2*wTrch);
    skip(-lPolishMark);
    sw2(lStraight, wTrch, wIO);
    skip(-lPolishMark);
    sw2(lPolishMark, wPolishMark, 2*wIO+2*wTrch);
    
    cw2(rBend, angBend, wTrch, wIO);
    sw2(lPolishMark, wPolishMark, 2*wIO+2*wTrch);
    skip(-lPolishMark);    
    sw2(lTilt,wTrch, wIO);
    skip(-0.5*lTilt);
    sw2(lPolishMark, wPolishMark, 2*wIO+2*wTrch);
    pop_cp();    
    
    dis2Edge = lGuide + lTaper + lStraight + rBend*sin(angBend) + lTilt*cos(angBend);
    return dis2Edge;
}
void padsVLSI(bool FlagShort=false){
    double lPad = 17e-6;
    double wPad = 17e-6;
    double pitch = 48.6e-6;
    double wWire = 10e-6;
    
    push_cp();    
    rotate(RAD(90)); /* Turn around 90*/
    skip(-lPad*0.5);
    sw2(lPad, wPad, pitch-wPad);
    if(FlagShort){
      pop_cp();push_cp();
      rotate(RAD(90));
      skip(-wWire*0.5);
      sw(wWire, pitch);
    }
    pop_cp();
}
void cell_Pads_TestB(int L){
    //start:  stop
    double pitch = 48.6e-6;
    double wWire = 9e-6;
    double lExtend = 1100e-6+315.9e-6;//shift the pad to the same column with the EAMs. 20120822
    double radius = 50e-6;
    double ldis = 50e-6;
    double pitch2 = 100e-6;
    double lPad2 = 150e-6;
    double wPad2 = 75e-6;
    
    layer(LPROBE);
    push_cp();
    
    padsVLSI(true);
    skip(-947.7e-6+315.9e-6);
    padsVLSI(false);
    
    push_cp();
    
    skip(-315.9e-6-315.9e-6);
    padsVLSI(true);
    
    pop_cp();
    skip(0.5*pitch);
    
    push_cp();
    rotate(-RAD(90));    
    cw(radius, -RAD(90), wWire);
    sw(lExtend-radius, wWire);
    cw(radius, -RAD(90), wWire);
    sw(100e-6, wWire);
    cw(radius, RAD(90), wWire);
    sw(lPad2, wPad2);
    
    pop_cp();push_cp();
    rotate(RAD(90));    
    cw(18.5e-6, RAD(90), wWire/2);//revised
    sw(150e-6, wWire/2);
    offset(0.5*wWire/2);
    rect(wWire, radius-18.5e-6+wWire/2, 1, 7);
    offset(0.5*wWire/2);
    
    sw(lExtend-radius-3*ldis-150e-6+radius-18.5e-6, wWire);       
    cw(radius, -RAD(90), wWire);
    sw(100e-6+pitch2*3-2*radius, wWire);
    cw(radius, RAD(90), wWire);
    sw(3*ldis, wWire);
    sw(lPad2, wPad2);

    pop_cp(); skip(-pitch); push_cp();    
    rotate(-RAD(90));    
    cw(radius*0.5, -RAD(90), wWire);
    sw(lExtend-pitch-radius*0.5-ldis, wWire);
    cw(radius, -RAD(90), wWire);
    sw(100e-6+pitch2-0.5*radius, wWire);
    cw(radius, RAD(90), wWire);
    sw(ldis, wWire);
    sw(lPad2, wPad2);    
    
    pop_cp();push_cp();
    rotate(RAD(180));    
    sw(220e-6, wWire);
    offset(0.5*wWire);
    rect(wWire, radius*0.5+wWire, 1, 7);
    offset(0.5*wWire);    
    sw(lExtend-pitch-radius*0.5-2*ldis-220e-6+radius*0.5, wWire);
    cw(radius, -RAD(90), wWire);
    sw(100e-6+pitch2*2-1.5*radius, wWire);
    cw(radius, RAD(90), wWire);
    sw(2*ldis, wWire);
    sw(lPad2, wPad2);    
   
    pop_cp();
    pop_cp();
}

double mmi_1x2_unit(double lMMI, double wMMI, double wWg, double wTrch){
    //double wMMI = 6e-6;
    //double lMMI = 39.6e-6;
    //double wWg = 1.5e-6;
    
    
    if(wTrch>0){//draw expanded version for boolean operation.
        layer(LSI3);
        push_cp();
        mmi_1x2(lMMI, wMMI+2*wTrch, wWg+2*wTrch, 0, -0.25*wMMI, 0.25*wMMI, RAD(56));
        pop_cp();
    }
    layer(LSI2);
    mmi_1x2(lMMI, wMMI, wWg, 0, -0.25*wMMI, 0.25*wMMI, RAD(56));
    
    return 0.5*wMMI;
}


void cell_mmi_test(int L){
    double wMMI = 6e-6;
    double lMMI = 39.6e-6;
    double wWg = P1_wWg;
    double wTrch = P1_wTrch;
    double dl = 2.5e-6; // deviation of the length
    
    double lArea = 1941e-6 - 700e-6;//compatible with the OTDM pattern
    double xL = 800e-6;    
    double xR = lArea - xL;
    double dis, z;
    double s = 30e-6;
    double r = 100e-6;
    
    double wWgG = P1_wWg+2*P1_wTrch;

    for(int i=-1; i<2; i++)
    {
            push_cp();
        rotate(RAD(180));
        POEM_IO(xL, P1_aIO, wWg, P1_wIO);
            pop_cp();
        
            push_cp();        
        dis = mmi_1x2_unit(lMMI+i*dl, wMMI, wWg, wTrch);
        //mmi_1x2(lMMI+i*dl, wMMI, P1_wWg, 0, -0.25*wMMI, 0.25*wMMI, RAD(56));
        //dis = 0.5*wMMI;
                push_cp();layer(LSI3);                    
        z = sbend(-s*0.5, r, 0, wWg+2*wTrch);
                pop_cp();layer(LSI2);
                push_cp();
        z = sbend(-s*0.5, r, 0, wWg); 
        POEM_IO(xR-lMMI-i*dl-z, P1_aIO, wWg, P1_wIO);
                pop_cp();
        offset(dis);
        
                push_cp();layer(LSI3);
        z = sbend(s*0.5, r, 0, wWg+2*wTrch);
                pop_cp();layer(LSI2);
        z = sbend(s*0.5, r, 0, wWg);  
          
        POEM_IO(xR-lMMI-i*dl-z, P1_aIO, wWg, P1_wIO);    
            pop_cp();
                 
               
        offset(2*s);
    }
    
}

double OTDM_A(){
    double wMMI = 6e-6;
    double lMMI = 39.6e-6;
    double wWg = P1_wWg;
    double wTrch = P1_wTrch;
    
    double dis = 0;
    double r = 100e-6;
    double ySW = 299.9e-6;
    
    double lEx = 10e-6;
    double dyPort = 0;
    
    layer(LSI);
    sw2(lEx, wTrch, wWg);//input waveguide
    dis = mmi_1x2_unit(lMMI, wMMI, wWg, wTrch);
        push_cp();
    
    layer(LSI3);
    cw(r, -RAD(90), wWg+2*wTrch);
        pop_cp();
        push_cp();
    layer(LSI2);
    cw(r, -RAD(90), wWg);
    
    layer(LSI);
    sw2(ySW, wTrch, wWg);
    cw2(r, RAD(90), wTrch, wWg); 
    
        pop_cp();
    offset(dis);
        push_cp();layer(LSI3);
    sw(2*r, wWg+2*wTrch);
        pop_cp();layer(LSI2);
    sw(2*r, wWg);
                
              
    dyPort = dis+ 2*r+ySW;
    #ifdef DEBUG
	  fprintf(stderr, "delta L in Part A: %g\n", 1e6*(r*PI-2*r+ySW));
	#endif
    
    return dyPort;
}
double OTDM_A_unit(int type){
    double dy = 0;
    struct pointer cpo;
    double dx1 = 0;
    double dx2 = 0;
    
    double lEAM = 100e-6;
    double lEx= 0e-6;
    
    double wPm;
    
    if(type==0){
        wPm=2.5e-6;
    }
    if(type==1){
        wPm=3e-6;
    }
    
    push_cp();
    cpo = cp;
    dy = OTDM_A();
    dx1 = cp.x-cpo.x;
    
    push_cp();
    move(0,0,0,FLIP);
    EAM_B(lEAM, lEx, wPm, 1);
    dx2 = cp.x-cpo.x;
    pop_cp();push_cp();    
    offset(-dy);
    EAM_B(lEAM, lEx, wPm, 1);
    pop_cp();
    offset(-dy*0.5);//dummy EAM.
    EAM_B(lEAM, lEx, wPm, 1);    
    
    pop_cp();
    skip(dx1+dx2);
    push_cp();
    move(0,0,-RAD(180), FLIP);
    OTDM_A();
    pop_cp();
    return dx1+dx2;
}
double OTDM_B(){
    double wMMI = 6e-6;
    double lMMI = 39.6e-6;
    double wWg = P1_wWg;
    double wTrch = P1_wTrch;
    
    double dis = 0;
    double r = 100e-6;
    double ySW1 = 750.19e-6;
    double ySW2 = 0e-6;
    
    double aSbend = 60;
    double lEx = 10e-6;
    double dyPort = 0;
    double lEx2 =0;
    
    
    layer(LSI);
    sw2(lEx, wTrch, wWg);//input waveguide
    dis = mmi_1x2_unit(lMMI, wMMI, wWg, wTrch);
        push_cp();
    
    layer(LSI3);
    cw(r, -RAD(90), wWg+2*wTrch);
        pop_cp();
        push_cp();
    
    layer(LSI2);
    cw(r, -RAD(90), wWg);
    layer(LSI);
    sw2(ySW1, wTrch, wWg);
    cw2(r, RAD(90), wTrch, wWg);
    
        pop_cp();
    offset(dis);
        push_cp(); layer(LSI3);
    cw(r, RAD(aSbend), wWg+2*wTrch);
        pop_cp(); layer(LSI2);
    cw(r, RAD(aSbend), wWg);
    
    layer(LSI);
    sw2(ySW2, wTrch, wWg);
    cw2(-r,-RAD(aSbend), wTrch, wWg);
    lEx2 = 2*r-2*r*sin(aSbend*PI/180.);  
    sw2(lEx2, wTrch, wWg);     
       
    dyPort = dis+ 2*r+2*r*(1-cos(aSbend*PI/180.))+ySW1+ySW2;
    #ifdef DEBUG
	  fprintf(stderr, "delta L in Part B: %g\n", 1e6*(r*PI+ySW1-2*r*aSbend*PI/180-ySW2-lEx2));
	#endif
    
    return dyPort;
}
void cell_OTDM(int L){
    org(0,0,0,NOFLIP);
    move(357.714e-6, -23.623e-6, 0, NOFLIP);
    push_cp();
    func_OTDM(0);
    pop_cp();
    offset(1250e-6);
    func_OTDM(1);
}
void func_OTDM(int type){
    double dy = 0;
    struct pointer cpo = cp;
    double dx1 = 0;
    double dx2 = 0;
    double lEx = 10e-6;
    
    push_cp();
    rotate(RAD(180));
    POEM_IO(lEx, P1_aIO, P1_wWg, P1_wIO);
    pop_cp();push_cp(); 
    dy = OTDM_B();
    dx1 = cp.x-cpo.x;
    push_cp();
    OTDM_A_unit(type);
    dx2 = cp.x-cpo.x;
    pop_cp();
    move(0,dy,0, FLIP);
    OTDM_A_unit(type);
    pop_cp();
    skip(dx1+dx2);
    push_cp();
    move(0,0,-RAD(180), FLIP);
    OTDM_B();
    pop_cp();
    POEM_IO(lEx, P1_aIO, P1_wWg, P1_wIO);
    //return dx1+dx2;    
}

double EAM_A(double l, double wPm){

    double disViaMargin=1e-6;

    double wSiRib = 1.0e-6;
    double wSiTrch = 2.5e-6;
    double wPmesa = wPm;
    double wQW = wPm + 4e-6;
    double wNmesa = 32e-6;
    double wGapNmetal = 8e-6;
    double wPmetal = wPm+1e-6;
    double wVia = 3e-6;
    double wProbe = wPmetal-0.5e-6;
    double wImpl = 20e-6;
    double lImpl = 10e-6;
    
    double wSiRibIn = 1.5e-6;
    double wTaperTip = 0.5e-6;
    double lTaperPmesa = 50e-6;
    double lTaperQW = 58e-6;
    double lTaperNmesa = 60e-6;
    double lTaperSi = lTaperNmesa;
    double lViaEdge = 0.5*lTaperNmesa;
    
    double wViaGND = 15e-6;
    double lViaGND = 20e-6;
    double wGapViaGND = wGapNmetal*1.25;
    
    double wProbeWire = wProbe*1.5;
    double lProbeWire = wNmesa*0.5+2e-6;
    double wPpad = 17e-6;
    double lPpad = wPpad;
    double wNpad = wPpad;
    double lNpad = 17e-6;
    double disPad = 48.6e-6;
    
    double lxSiOffset = 0;
    
    {layer(LSI);
    push_cp();
    skip(lTaperNmesa);
    push_cp();
    rotate(RAD(180)); /* Turn around */
    taper2(lTaperSi, wSiTrch,wSiTrch, wSiRib, wSiRibIn);
    pop_cp();
    push_cp();
    sw2(l, wSiTrch, wSiRib);
    taper2(lTaperSi, wSiTrch,wSiTrch, wSiRib, wSiRibIn);
    pop_cp();}
    
    {layer(LPMESA);    
    push_cp();
    rotate(RAD(180)); /* Turn around */
    taper(lTaperPmesa, wPmesa, wTaperTip);
    disc(wTaperTip*0.5);
    pop_cp();
    push_cp();
    sw(l, wPmesa);
    taper(lTaperPmesa, wPmesa, wTaperTip);
    disc(wTaperTip*0.5);
    pop_cp();}
    
    {layer(LQW);
    push_cp();
    rotate(RAD(180)); /* Turn around */
    taper(lTaperQW, wQW, wTaperTip);
    disc(wTaperTip*0.5);
    pop_cp();
    push_cp();    
    //sw(l,wNmesa);//in future, merge LQW and LNMESA.
    sw(l*0.5-wProbeWire, wNmesa);
    push_cp();
    offset(-(0.5*wNmesa-0.5*wGapNmetal)*0.5);
    sw(2*wProbeWire, 0.5*(wNmesa+wGapNmetal));
    pop_cp();
    skip(2*wProbeWire);
    sw(l*0.5-wProbeWire, wNmesa);
    
    taper(lTaperQW, wQW, wTaperTip);
    disc(wTaperTip*0.5);    
    pop_cp();push_cp();
    skip(-lViaEdge);
    sw2(lViaEdge, (wNmesa-wGapNmetal)*0.5, wGapNmetal);
    skip(l);
    sw2(lViaEdge, (wNmesa-wGapNmetal)*0.5, wGapNmetal);
    pop_cp();}
    

    {layer(LNMESA);
    push_cp();
    rotate(RAD(180)); /* Turn around */
    sw(lViaEdge, wNmesa);
    taper(lTaperNmesa-lViaEdge, wSiTrch*3, wTaperTip);
    disc(wTaperTip*0.5);
    pop_cp();
    push_cp();    
   // sw(l, wNmesa);  
    sw(l*0.5-wProbeWire, wNmesa);
    push_cp();
    offset(-(0.5*wNmesa-0.5*wGapNmetal)*0.5);
    sw(2*wProbeWire, 0.5*(wNmesa+wGapNmetal));
    pop_cp();
    skip(2*wProbeWire);
    sw(l*0.5-wProbeWire, wNmesa);  
    
    sw(lViaEdge, wNmesa);
    taper(lTaperNmesa-lViaEdge, wSiTrch*3, wTaperTip);
    disc(wTaperTip*0.5);    
    pop_cp();
    push_cp();
    skip(-lViaEdge);
    sw2(lViaGND, wViaGND, wGapViaGND);
    skip(2*lViaEdge+l-2*lViaGND);
    sw2(lViaGND, wViaGND, wGapViaGND);
    pop_cp();}
        
    {layer(LNMTL);
    push_cp();
    skip(-lViaEdge);
    //sw2(lViaEdge*2+l, (wNmesa-wGapNmetal)*0.5, wGapNmetal);
    
    sw2(lViaEdge+l*0.5-wProbeWire, (wNmesa-wGapNmetal)*0.5, wGapNmetal);
    push_cp();
    offset(-( (wNmesa-wGapNmetal)*0.25+wGapNmetal*0.5));
    sw(wProbeWire*2, (wNmesa-wGapNmetal)*0.5);
    pop_cp();
    skip(wProbeWire*2);
    sw2(lViaEdge+l*0.5-wProbeWire, (wNmesa-wGapNmetal)*0.5, wGapNmetal);    
    
    skip(-lViaEdge*2-l);
    sw2(lViaGND, wViaGND, wGapViaGND);
    skip(2*lViaEdge+l-2*lViaGND);
    sw2(lViaGND, wViaGND, wGapViaGND);    
    pop_cp();}
    
    {layer(LIMPL);
    push_cp();
    rotate(RAD(180)); /* Turn around */
    sw(lImpl, wImpl);
    pop_cp();
    push_cp();
    skip(l);
    sw(lImpl, wImpl);
    pop_cp();}
    
    {layer(LPMTL);
    push_cp();    
    sw(l, wPmetal);    
    pop_cp();push_cp();
    //short the taper to the ground
    skip(-lViaEdge);
    sw(lViaGND, wPmetal);
    skip(2*lViaEdge+l-2*lViaGND);
    sw(lViaGND, wPmetal);
    pop_cp();}       
    
    {layer(LVIA);
    push_cp();
   // skip(disViaMargin);
   // sw(l-2*disViaMargin, wVia);
   // pop_cp();push_cp();
    skip(-lViaEdge+disViaMargin);
    //sw3(lViaGND-2*disViaMargin, wVia, 0.5*(wGapViaGND-wVia), wViaGND);    
    sw2(lViaGND-2*disViaMargin, wViaGND, wGapViaGND); 
    skip(l+2*lViaEdge-2*lViaGND+2*disViaMargin);
   // sw3(lViaGND-2*disViaMargin, wVia, 0.5*(wGapViaGND-wVia), wViaGND);
    sw2(lViaGND-2*disViaMargin, wViaGND, wGapViaGND);
    pop_cp();}
    
    
    {layer(LPROBE);
    push_cp();
    skip(-lViaEdge);
    sw(lViaGND, wViaGND*2+wGapViaGND);
    pop_cp();push_cp();
    sw(l, wProbe); 
    skip(lViaEdge-lViaGND);
    sw(lViaGND, wViaGND*2+wGapViaGND);    
    pop_cp();push_cp();
    skip(l*0.5);
    rotate(RAD(90)); /* Turn around */
    sw(lProbeWire, wProbeWire);}
    
    if(lNpad<wPpad*0.5+l*0.5+lViaEdge-disPad) lNpad=wPpad*0.5+l*0.5+lViaEdge-disPad;
    sw3(lPpad, wPpad, disPad-wPpad, lNpad);
    pop_cp();
    
    pop_cp();
    skip(l+2*lTaperNmesa); //move the cp to the end of the waveguide.
    
    lxSiOffset = 2*lTaperSi + l;
    #ifdef DEBUG
        fprintf(stderr, "Pad relative position: %g, %g\n",lxSiOffset*0.5, lPpad*0.5+lProbeWire);
    #endif
    return lxSiOffset;
}

void func_EAM_B_array(int type){
    double lEAM = 100e-6;
    double dl  = 100e-6;    
    double lEx  = 0e-6;
    double dEx = 5e-6;   
    double ypitch = 250e-6;
    double xR = 1200e-6;
    double xL = 100e-6;
    double nr = 4;
    double nc = 3;
    double dx = 350e-6;
    double dy = ypitch/nc;
    double lEAM_total;
    double wPm = 2.5e-6;
    char temp[10];
    if(type==0){
        wPm = 2.5e-6;
    }
    if(type==1){
        wPm = 3.0e-6;
    }
    
    push_cp();   
    for(int j=0; j<nc; j++){
        push_cp();
        move(dx*j, -dy*j, 0, NOFLIP);        
        for(int i=0; i<nr; i++){
            {
                push_cp();
                rotate(RAD(180));
                POEM_IO(xL+j*dx, P1_aIO, P1_wWg, P1_wIO);
                pop_cp();
            }        
            {
                push_cp();
                lEAM_total = EAM_B(lEAM-2*dEx*i, lEx+dEx*i, wPm);
                POEM_IO(xR-j*dx-lEAM_total, P1_aIO, P1_wWg, P1_wIO);
                pop_cp();
            }
            if(j==0){
                push_cp();
                skip(-(xL+j*dx));
                offset(-(P1_wWg+P1_wTrch));                    
                sprintf(temp, "%d", i+1);
                textout(temp, 25e-6);
                pop_cp();
                push_cp();
                skip((xR-j*dx));
                offset(-(P1_wWg+P1_wTrch)); 
                textout(temp, 25e-6);
                pop_cp();                    
            }
            
            push_cp();
                offset(dy*0.5);
                push_cp();
                POEM_IO(xR-j*dx, P1_aIO, P1_wWg, P1_wIO);
                pop_cp(); push_cp();
                rotate(RAD(180));
                POEM_IO(xL+j*dx, P1_aIO, P1_wWg, P1_wIO);
                pop_cp();
            pop_cp();
            offset(ypitch);            
        }        
        pop_cp();
        lEAM += dl;        
    }
    pop_cp(); 
    
}
void cell_EAM_B_array(int L){
    org(0,0,0,NOFLIP);
    func_EAM_B_array(0);
    org(0,-1100e-6,0,NOFLIP);
    func_EAM_B_array(1);
}

void cell_EAM_Array(int L){//relative to the (0,0)
    org(0,0,0,NOFLIP);//flipped.
    func_EAM_Array(0);
    org(0,-P1_DY, 0, NOFLIP);
    func_EAM_Array(1);
}
void func_EAM_Array(int type){//relative to the center 
    double lEAM = 100e-6;       
    double ypitch = 249.9975e-6;
    double lArea = 7800e-6 - 700e-6;
    double lEAM_Total = 220e-6;
    
    double xOffset = 1849.23e-6 + lEAM_Total*0.5 + 24.3e-6;//to the center of the cell        
    double xP = lEAM_Total*0.5+24.3e-6;// center of the two pads to the start of the EAM tip.
    double yP = 26.5e-6; // to the start of the EAM tip
    
    double xL = lArea/2-xOffset;    
    double xR = lArea - xL;

    double nr = 8;
    double nc = 2;
    //double dx = 160e-6;
    double dx = 0e-6;
    double dy = 126.36e-6;
    char temp[10];
    
    double revision_offset = 0e-6;//no necessary to shift now.
    
    double wPm = 2.5e-6;
    if(type==0){
        wPm = 2.5e-6;
    }
    if(type==1){ 
        wPm = 3e-6;
    }
    
    //move(-1849.23e-6,836.12e-6, 0, NOFLIP);
    offset(-836.12e-6);
    skip(-xOffset+xP);//move to the center of the two pads (first column);    
    push_cp();//save the center position of the two pads.
    
    skip(-xP);
    offset(-yP);//move to the start of the EAM
    
    for(int j=0; j<nc; j++){
        push_cp();
        move(dx*j, dy*j, 0, NOFLIP);
        for(int i=0; i<nr; i++){        
            {
                push_cp();
                lEAM_Total = EAM_A(lEAM, wPm);
                POEM_IO(xR-j*dx-lEAM_Total, P1_aIO, P1_wWg, P1_wIO);
                pop_cp();
            }
            {
                push_cp();
                rotate(RAD(180));
                POEM_IO(xL+j*dx, P1_aIO, P1_wWg, P1_wIO);
                pop_cp();
            }
            {
                if(j==0){
                    push_cp();
                    skip(-(xL+j*dx));
                    offset(40e-6);                    
                    sprintf(temp, "%d", i+1);
                    textout(temp, 30e-6);
                    pop_cp();
                    push_cp();
                    skip((xR-j*dx));
                    offset(40e-6); 
                    textout(temp, 30e-6);
                    pop_cp();                    
                }            
            }            
            offset(ypitch);
        }
        pop_cp();        
    }
    
    
    pop_cp();
    skip(-revision_offset); //for revision to shift the pads to the left by a pad pitch. 20120821
    push_cp();//go back to the center of the two pads
    //put one offset pads in testPads_B for the offset 1x8 EAM array for location and testing. 
    layer(LPROBE);
    /*move(631.8e-6, 201.4e-6, 0, NOFLIP);
    move(dx, -dy, 0, NOFLIP);    
    padsVLSI(true);
    move(0,-2075.018e-6, 0, NOFLIP);
    padsVLSI(true);
    move(1217.43e-6*2,0,0, NOFLIP);
    padsVLSI(true);
    move(0, 2075.018e-6, 0, NOFLIP);
    padsVLSI(true);
    */
    pop_cp();push_cp();
    //move to the start position of the testPads_B
    move(315.9e-6*2, 201.4e-6, 0, NOFLIP);
    cell_Pads_TestB(0);
    //move to the other testPads_B
    move(0,-2075.018e-6,0,FLIP);
    cell_Pads_TestB(0);
    move(1217.43e-6*2,0,RAD(180),FLIP);
    cell_Pads_TestB(0);
    move(0, -2075.018e-6, 0, FLIP);
    cell_Pads_TestB(0); 
    
    move(-315.9e-6*2, 0, RAD(180), FLIP);
    offset(75.04e-6);
    for(int j=0; j<nc; j++){
        push_cp();
        move(dx*j, -dy*j, 0, NOFLIP);
        for(int i=0; i<nr; i++){        
            padsVLSI(false);           
            offset(ypitch);
        }
        pop_cp();        
    }   
    pop_cp();  
}

void cell_PD_LD(int L){//dummy EAM used as PD and LDs. Need post process for the pads      
    double xL = 850e-6;
    double wPm = 2.5e-6;
    int nr = 8;
    double ypitch = 250e-6;
    //wPm = 2.5e-6
    push_cp();    
    for(int i=0; i<nr; i++){
    push_cp();
    rotate(RAD(180));
    POEM_IO(xL, P1_aIO, P1_wWg, P1_wIO);
    pop_cp();
    push_cp();
    EAM_A(100e-6, wPm);//PDs
    layer(LSI);
    sw2(50e-6, P1_wTrch, P1_wWg);
    EAM_A(250e-6, wPm);//LDs
    pop_cp();
    offset(ypitch);
    }
    
    //wPm = 3e-6
    wPm = 3e-6;
    pop_cp();
    offset(P1_DY);
    for(int i=0; i<nr; i++){
    push_cp();
    rotate(RAD(180));
    POEM_IO(xL, P1_aIO, P1_wWg, P1_wIO);
    pop_cp();
    push_cp();
    EAM_A(100e-6, wPm);//PDs
    layer(LSI);
    sw2(50e-6, P1_wTrch, P1_wWg);
    EAM_A(250e-6, wPm);//LDs
    pop_cp();    
    offset(ypitch);
    }
}

void cell_EAM_B_TestTaper(int L){
    org(0,0,0, NOFLIP);
    func_EAM_B_TestTaper(0);
    org(0,-P1_DY, 0, NOFLIP);
    func_EAM_B_TestTaper(1);
}
void func_EAM_B_TestTaper(int type){
    double lEAM = 600e-6;
    double lEx  = 0e-6;    
    double ypitch = 249.9975e-6;
    double lArea = 7800e-6 - 700e-6;
    double xL = 2400e-6;
    double xR = lArea-xL;    
    int nc[] = {6,5,4,3,2,2,1,0,0};
    int nr = sizeof(nc)/sizeof(nc[0]);
    double dlWg = 100e-6;
    
    double lEAM_total;
    
    double wPm = 2.5e-6;
    if(type==0){
        wPm = 2.5e-6;
    }
    if(type==1){
        wPm = 3.0e-6;
    }
    
    skip((xR-xL)*0.5);
    push_cp();
    for(int j=0; j<nr; j++){
        push_cp();
        rotate(RAD(180));
        POEM_IO(xL, P1_aIO, P1_wWg, P1_wIO);
        pop_cp();push_cp();
        for(int i=0; i<nc[j]; i++){       
            lEAM_total = EAM_B(lEAM/nc[j], lEx, wPm);
            layer(LSI);
            sw2(dlWg, P1_wTrch, P1_wWg);
        } 
        POEM_IO(xR-(nc[j])*(lEAM_total+dlWg), P1_aIO, P1_wWg, P1_wIO);        
        pop_cp();
        offset(ypitch);    
    }
    
    pop_cp();
}
void cell_EAM_B_TestLen(int L){
    org(0,0,0,NOFLIP);
    func_EAM_B_TestLen(0);
    org(0,-P1_DY, 0, NOFLIP);
    func_EAM_B_TestLen(1);
}
void func_EAM_B_TestLen(int type){
    double lEAM = 100e-6;
    double lEx  = 0e-6;    
    double ypitch = 249.9975e-6;
        
    double lArea = 7800e-6 - 700e-6;
    double xR = 2775e-6;//left blank straight waveguide
    double xL = lArea - xR;//
    
    double lens[] = {1200e-6, 1000e-6, 800e-6, 600e-6, 400e-6, 300e-6, 200e-6, 100e-6, 0e-6};  
    int nr = sizeof(lens)/sizeof(lens[0]);;
    double lEAM_total;
    
    double wPm = 2.5e-6;
    if(type==0){
        wPm = 2.5e-6;
    }
    if(type==1){
        wPm = 3.0e-6;
    }
    
    skip((xL-xR)/2);//move from the middle to the right starting point
    push_cp();
    for(int j=0; j<nr; j++){
        push_cp();
        POEM_IO(xR, P1_aIO, P1_wWg, P1_wIO);
        pop_cp();push_cp();
        rotate(RAD(180));
        lEAM = lens[j];
        if(lEAM>10e-6)
        {
            move(0,0,0,FLIP);
            lEAM_total = EAM_B(lEAM, lEx, wPm);
            move(0,0,0,FLIP);
        }
        else
        {
            lEAM_total = 0;
        }
        POEM_IO(xL-lEAM_total, P1_aIO, P1_wWg, P1_wIO);       
        pop_cp();
        offset(-ypitch);
    }
    pop_cp();
}


double EAM_B(double l, double lEx, double wPm, int padType){

    double disViaMargin=1e-6;

    double wSiRib = 1.0e-6;
    double wSiTrch = 2.5e-6;
    double wPmesa = wPm;
    double wQW = wPm + 4e-6;
    double wNmesa = 32e-6;
    double wGapNmetal = 8e-6;
    double wPmetal = wPm+1e-6;
    double wVia = 3e-6;
    double wProbe = wPmetal-0.5e-6;
    double wImpl = 20e-6;
    double lImpl = 10e-6;
    
    double wSiRibIn = 1.5e-6;
    double wTaperTip = 0.5e-6;
    double lTaperPmesa = 50e-6;
    double lTaperQW = 58e-6;
    double lTaperNmesaT = 30e-6;
    double lTaperNmesaW = 30e-6;
    double lTaperNmesa = lTaperNmesaT + lTaperNmesaW;    
    double lTaperSi = lTaperNmesa;

    
    double lViaEdge = 0.5*lTaperNmesa;
    
    double wViaGND = 15e-6;
    double lViaGND = 20e-6;
    double wGapViaGND = wGapNmetal*1.25;
    
    double wProbeWire = wProbe*1.5;
    double lProbeWire = wNmesa*0.5+2e-6;
    
    //double wPpad = 17e-6;
    //double lPpad = wPpad;
    //double disPad = 48.6e-6;
    
    double wPpad, lPpad, wNpad, lNpad, disPad;
    
    if (padType==0){
        wPpad = 50e-6;
        lPpad = 75e-6;
        lNpad = lPpad;
        wNpad = 75e-6;//design A    
        disPad = 100e-6;
    }
    if (padType==1){//OTDM pad for wire bonding
        wPpad = 80e-6;
        lPpad = 100e-6;
        lNpad = lPpad;
        wNpad = 200e-6;//design A    
        disPad = 100e-6;
    }
    
    double lImplOffset = lEx;//design A
    
    double lxSiOffset = 0;
    
    if(lViaGND>(lViaEdge-lImpl-lImplOffset)) lViaEdge = lViaGND +lImpl +lImplOffset;
    
    {layer(LSI);
    push_cp();
    skip(lTaperNmesa);
    push_cp();
    rotate(RAD(180)); /* Turn around */
    taper2(lTaperSi, wSiTrch,wSiTrch, wSiRib, wSiRibIn);
    pop_cp();
    push_cp();
    sw2(l, wSiTrch, wSiRib);
    taper2(lTaperSi, wSiTrch,wSiTrch, wSiRib, wSiRibIn);
    pop_cp();}
    
    {layer(LPMESA);    
    push_cp();
    rotate(RAD(180)); /* Turn around */
    taper(lTaperPmesa, wPmesa, wTaperTip);
    disc(wTaperTip*0.5);
    pop_cp();
    push_cp();
    sw(l, wPmesa);
    taper(lTaperPmesa, wPmesa, wTaperTip);
    disc(wTaperTip*0.5);
    pop_cp();}
    
    {layer(LQW);
    push_cp();
    rotate(RAD(180)); /* Turn around */
    taper(lTaperQW, wQW, wTaperTip);
    disc(wTaperTip*0.5);
    pop_cp();
    push_cp();    
   // sw(l, wQW);
    skip(-lImplOffset);
    sw(l*0.5+lImplOffset-wProbeWire, wNmesa);
    push_cp();
    offset(-(0.5*wNmesa-0.5*wGapNmetal)*0.5);
    sw(2*wProbeWire, 0.5*(wNmesa+wGapNmetal));
    pop_cp();
    skip(2*wProbeWire);
    sw(l*0.5+lImplOffset-wProbeWire, wNmesa);
    
    skip(-lImplOffset);
    taper(lTaperQW, wQW, wTaperTip);
    disc(wTaperTip*0.5);    
    pop_cp();push_cp();
    skip(-lViaEdge);
    sw2(lViaEdge, (wNmesa-wGapNmetal)*0.5, wGapNmetal);
    skip(l);
    sw2(lViaEdge, (wNmesa-wGapNmetal)*0.5, wGapNmetal);
    pop_cp();}    

    {layer(LNMESA);
    push_cp();
    rotate(RAD(180)); /* Turn around */
    sw(lTaperNmesaW, wNmesa);
    taper(lTaperNmesaT, wSiTrch*3, wTaperTip);
    disc(wTaperTip*0.5);
    pop_cp();
    push_cp();    
    //sw(l, wNmesa);
    sw(l*0.5-wProbeWire, wNmesa);
    push_cp();
    offset(-(0.5*wNmesa-0.5*wGapNmetal)*0.5);
    sw(2*wProbeWire, 0.5*(wNmesa+wGapNmetal));
    pop_cp();
    skip(2*wProbeWire);
    sw(l*0.5-wProbeWire, wNmesa);  
    
    sw(lTaperNmesaW, wNmesa);
    taper(lTaperNmesaT, wSiTrch*3, wTaperTip);
    disc(wTaperTip*0.5);    
    pop_cp();
    push_cp();
    skip(-lViaEdge);
    sw2(lViaGND, wViaGND, wGapViaGND);
    skip(2*lViaEdge+l-2*lViaGND);
    sw2(lViaGND, wViaGND, wGapViaGND);
    pop_cp();}
        
    {layer(LNMTL);
    push_cp();
    skip(-lViaEdge);
    sw2(lViaEdge+l*0.5-wProbeWire, (wNmesa-wGapNmetal)*0.5, wGapNmetal);
    push_cp();
    offset(-( (wNmesa-wGapNmetal)*0.25+wGapNmetal*0.5));
    sw(wProbeWire*2, (wNmesa-wGapNmetal)*0.5);
    pop_cp();
    skip(wProbeWire*2);
    sw2(lViaEdge+l*0.5-wProbeWire, (wNmesa-wGapNmetal)*0.5, wGapNmetal);
    
    skip(-lViaEdge*2-l);
    sw2(lViaGND, wViaGND, wGapViaGND);
    skip(2*lViaEdge+l-2*lViaGND);
    sw2(lViaGND, wViaGND, wGapViaGND);    
    pop_cp();}
    
    {layer(LIMPL);
    push_cp();
    rotate(RAD(180)); /* Turn around */
    skip(lImplOffset); //Design A
    sw(lImpl, wImpl);
    pop_cp();
    push_cp();
    skip(l);
    skip(lImplOffset);//Design A
    sw(lImpl, wImpl);
    pop_cp();}
    
    {layer(LPMTL);
    push_cp();
    //sw(l, wPmetal);//Baseline Design
    skip(-lImplOffset);//Design A    
    sw(l+2*lImplOffset, wPmetal); //Design A   
    pop_cp();push_cp();
    //short the taper to the ground
    skip(-lViaEdge);

    sw(lViaGND, wPmetal);
    skip(2*lViaEdge+l-2*lViaGND);
    sw(lViaGND, wPmetal);
    pop_cp();}
           
    {layer(LVIA);
    push_cp();
    skip(-lViaEdge+disViaMargin);
    sw2(lViaGND-2*disViaMargin, wViaGND, wGapViaGND);    
    skip(l+2*lViaEdge-2*lViaGND+2*disViaMargin);
    sw2(lViaGND-2*disViaMargin, wViaGND, wGapViaGND);
    pop_cp();}
    
    {layer(LPROBE);
    push_cp();
    skip(-lViaEdge);
    sw(lViaGND, wViaGND*2+wGapViaGND);
    pop_cp();push_cp();
    skip(-lImplOffset);
    sw(l+2*lImplOffset, wProbe); 
    skip(lViaEdge-lImplOffset-lViaGND);
    sw(lViaGND, wViaGND*2+wGapViaGND);    
    pop_cp();push_cp();
    skip(l*0.5);
    rotate(RAD(90)); /* Turn around */
    sw(lProbeWire, wProbeWire);}
    
    double minN = 30e-6;//min dis of the N probe center to the edge
    if(wNpad<l*0.5+lViaEdge-disPad+minN) wNpad=l*0.5+lViaEdge-disPad+minN;
    else{
        push_cp();
        skip(-lProbeWire-0.5*(wViaGND*2+wGapViaGND));
        sw2(wViaGND*2+wGapViaGND, wNpad+disPad-minN-lViaEdge-0.5*l, 2*lViaEdge+l);
        pop_cp();
    }
    sw3(lPpad, wPpad, disPad-0.5*wPpad-minN, wNpad);
    
    pop_cp();
        
    pop_cp();
    skip(l+2*lTaperNmesa); //move the cp to the end of the waveguide.
    
    lxSiOffset = lTaperSi*2+l;
    return lxSiOffset;
}

double spiral_square_sw2(double dx, int loops){
    //int    loops = 6; //loop number
    double r     = 150e-6; //bending radius
    double s     = 10e-6; // dis between two WGs.
    //double dx    = 100e-6; //insert space for different lengths

    double wWg   = P1_wWg; //waveguide width
    double wTr   = P1_wTrch; // trench width for sw2    
    
    double xlen   = dx+2*r+s*(loops*2-1);
    double ylen   = s*(2*loops-1);
    
    double lenTotal = 0;
    double dxOffset; //x shift of the cp;
    for(int i=0; i<loops; i++){
        sw2(xlen, wTr, wWg);
        cw2(r, RAD(90), wTr, wWg);
        sw2(ylen, wTr, wWg);
        cw2(r, RAD(90), wTr, wWg);
        lenTotal += (xlen+ylen+PI*r);
        xlen-=2*s;
        ylen-=2*s;
    }
    cw2(r, RAD(90), wTr, wWg);
    cw2(-r, -RAD(90), wTr, wWg);
    sw2(dx, wTr, wWg);
    lenTotal += (dx+PI*r);
    
    ylen = s;
    xlen = dx+2*r+s;
    for(int i=0; i<loops; i++){
        cw2(-r, -RAD(90), wTr, wWg);        
        sw2(ylen, wTr, wWg);
        cw2(-r, -RAD(90), wTr, wWg);        
        sw2(xlen, wTr, wWg);
        lenTotal += (xlen+ylen+PI*r);        
        ylen += 2*s;
        xlen += 2*s;      
    }
    #ifdef DEBUG
	  fprintf(stderr, "Total Length except IO: %g\n", (lenTotal-xlen+s)*1e6);
	#endif
    return dxOffset = xlen-s;
}
void cell_wg_loss(int L){
    double lArea = 7800e-6 - 700e-6;
    double xL = 100e-6;    
    double xR = lArea - xL;
    double ypitch = 30e-6;
    double space = 300e-6;
    
    double dx = 10e-6;
    int    loops = 10;
    double delta = 300e-6;
    
    
    double xOffset = 0;
    
    layer(LSI);
    
    //length: 19596, 25596, 31596, 37596, 43596 + IO;
    
    for (int i=0; i<5; i++){
        push_cp();
        rotate(RAD(180));
        POEM_IO(xL, P1_aIO, P1_wWg, P1_wIO);
        pop_cp();push_cp();
        move(0,0,0,FLIP);
        xOffset = spiral_square_sw2(dx, loops);
        move(0,0,0,FLIP);
        POEM_IO(xR-xOffset, P1_aIO, P1_wWg, P1_wIO);
        pop_cp();
        
        offset(ypitch);
        skip(xOffset+space);
        xL += xOffset+space;
        xR = lArea - xL;
        dx +=delta;
    }//
}

void cell_label_polarity(int L){
    double ftsize = 75e-6;
    for(int i=0; i<taperOutLayers; i++){
        push_cp();
        layer(taperOutID[i]);
        textout(taperOutPolarity[i], ftsize);
        pop_cp();
    }
}

void cell_Moire_line(int L){
    org(0,0,0,NOFLIP);
    push_cp();
    rotate(-RAD(90));
    int RefLayer = LSI;
    for (int i=0; i<taperOutLayers; i++){
        if(taperOutID[i]!= RefLayer){
            func_Moire_line(taperOutID[i], RefLayer);
        }
        skip(225e-6);
    }    
    pop_cp();
}
void func_Moire_line(int ObjLayer, int RefLayer){
    double a = 5.725; // M=~10
    push_cp();
    
    Moire_line(4e-6, 2e-6, a, ObjLayer, RefLayer);//M~10;
    skip(110e-6);
    Moire_line(4e-6, 1e-6, a, ObjLayer, RefLayer);//M~10;
    pop_cp();push_cp();
    offset(10e-6);
    rotate(RAD(90));
    Moire_line(4e-6, 2e-6, a, ObjLayer, RefLayer);//M~10;
    offset(-165e-6);
    
    for(int i=0; i<taperOutLayers; i++){
        if(ObjLayer == taperOutID[i]) textout(taperOutName[i], 20e-6);
    }
    pop_cp();
}
void Moire_line(double d, double w, double a, int ObjLayer, int RefLayer){
    int nlines = 13;
    int nCross = 5;//odd number will be good. it should be no less than 3
    double A = RAD(a);
    double W = d/(2*sin(A*0.5));//Moire pattern space
    double dy = (nCross-1)*W;
    double wline = w;
    
    push_cp();
    layer(ObjLayer);
    skip(wline*0.5);    
    push_cp();
    rotate(-RAD(90));
    for(int i=0; i<nlines; i++){
        push_cp();
        taper_angle(dy, A*0.5, wline, wline);
        pop_cp();
        offset(d);
    }
    pop_cp();
    layer(RefLayer); 
    push_cp();
    skip((nCross-1)/2*d);
    rotate(-RAD(90));
    for(int i=0; i<nlines; i++){
        push_cp();
        taper_angle(dy, -A*0.5, wline, wline);
        pop_cp();
        offset(d);
    }
    pop_cp();
    push_cp();//mark left
    rotate(RAD(180));
    for(int i=1; i<nCross-1; i++){
        offset(W);
        push_cp();
        sw(10e-6, wline);
        pop_cp();push_cp();
        offset(0.5*W);
        sw(5e-6, wline);
        pop_cp();
    }
    pop_cp();
    skip((nlines-1+(nCross-1)/2)*d);//mark right
    for(int i=1; i<nCross-1; i++){
        offset(-W);
        push_cp();
        sw(10e-6, wline);
        pop_cp();push_cp();
        offset(-0.5*W);
        sw(5e-6, wline);
        pop_cp();
    }    
    
    pop_cp();
}